package com.ophiux.gateway.config;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;

/**
 * @desc: 通过代码初始化流控规则 ①通过服务注入
 * sentinel规则配置，两种方式：①通过服务注入 ②通过配置文件加载
 * @author: hhl
 * @date：2023/5/19 18:11
 */
//@Component
public class SentinelRuleConfig implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        initGatewayGroupApiRules();
        initGatewayRules();
        initGatewayDegradeRules();
    }

    //配置网关分组api
    private void initGatewayGroupApiRules(){
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("ophiux-system-group-prefix")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/system/sentinel/testSlowRequest").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT));
                    add(new ApiPathPredicateItem().setPattern("/system/sentinel/testExceptionRatio").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT));
                }});
        definitions.add(api1);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

    /**
     * 配置网关限流规则
     */
    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("ophiux-system")
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID)
                .setGrade(1)
                // 限流阈值
                .setCount(1)
                // 统计时间窗口，单位是秒，默认是 1 秒
                .setIntervalSec(1)
                //快速失败和匀速排队
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
        );
        rules.add(new GatewayFlowRule("ophiux-product")
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID)
                .setGrade(1)
                .setCount(200)
                .setIntervalSec(1)
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
        );
        rules.add(new GatewayFlowRule("ophiux-system-group-prefix")
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
                .setGrade(1)
                .setCount(1)
                .setIntervalSec(1)
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
        );
        GatewayRuleManager.loadRules(rules);
    }

    //配置熔断规则
    private void initGatewayDegradeRules(){
        List<DegradeRule> rules = new ArrayList<>();
        rules.add(new DegradeRule("testSentinel")
                // 熔断策略，支持慢调用比例/异常比例/异常数策略
                .setGrade(RuleConstant.DEGRADE_GRADE_RT)
                // Max allowed response time    慢调用比例模式下为慢调用临界 RT（超出该值计为慢调用）；异常比例/异常数模式下为对应的阈值
                .setCount(10)
                // Retry timeout (in second) 熔断时长，单位为 s
                .setTimeWindow(1)
                // 熔断触发的最小请求数，请求数小于该值时即使异常比率超出阈值也不会熔断
                .setMinRequestAmount(1)
                // 统计时长（单位为 ms），如 60*1000 代表分钟级
                .setStatIntervalMs(1000)
                // Circuit breaker opens when slow request ratio > 60%  慢调用比例阈值，仅慢调用比例模式有效
                .setSlowRatioThreshold(0.1)
        );
        DegradeRuleManager.loadRules(rules);
    }
}